﻿using System;
using System.Collections.Generic;
using System.Linq;
using Web7.Ioc;
using System.Diagnostics;
using System.Threading;
using Autofac;
using Web7.Extensions;
using Autofac.Core;

namespace Web7.Core.IOC.Autofac
{
    /// <summary>
    /// autofac 依赖注入解析方案
    /// </summary>
    public class AutofacResolutionContext : IResolutionContext
    {
        private readonly IComponentContext _context;

        /// <summary>
        /// 初始化一个新的实例<see cref="T:System.Object"/> class.
        /// </summary>
        public AutofacResolutionContext(IComponentContext context)
        {
            _context = context;
        }

        public T Resolve<T>()
        {
            Debug.WriteLine("Resolve call for {0} on thread {1}".InvariantFormat(typeof(T).Name, Thread.CurrentThread.ManagedThreadId));
            try
            {
                return _context.Resolve<T>();
            }
            catch (Exception)
            {
                var registeredIds = _context.ComponentRegistry.Registrations.Select(x => x.Id).ToArray();
                var distinctIds = registeredIds.Distinct().ToArray();
                throw;
            }
        }

        public IEnumerable<T> ResolveAll<T>()
        {
            //要找到每个注册的服务，将那些匹配的类型T存储
            var allKeys = new List<object>();
            foreach (var componentRegistration in _context.ComponentRegistry.Registrations)
            {
                // 获取与KeyedService匹配的Service
                var typedServices = componentRegistration.Services.Where(x => x is KeyedService).Cast<KeyedService>();
                // 添加正确的类型T到allKeys
                allKeys.AddRange(typedServices.Where(y => y.ServiceType == typeof(T)).Select(x => x.ServiceKey));
            }

            //默认的
            var allUnKeyedServices = new List<T>(_context.Resolve<IEnumerable<T>>());
           
            allUnKeyedServices.AddRange(allKeys.Distinct().Select(key => _context.ResolveKeyed<T>(key)));

            //allUnKeyedServices+allKeys
            return allUnKeyedServices;
        }

        public T Resolve<T>(string name)
        {
            return _context.ResolveNamed<T>(name);
        }

        public object Resolve(Type type)
        {
            return _context.Resolve(type);
        }

        public IEnumerable<object> ResolveAll(Type type)
        {
            var enumerableServiceType = typeof(IEnumerable<>).MakeGenericType(type);
            var instance = _context.Resolve(enumerableServiceType);

            return (IEnumerable<object>)instance;
        }

        public object Resolve(Type type, string name)
        {
            return _context.ResolveNamed(name, type);
        }

        #region Implementation of IDisposable

        public void Dispose()
        {
            _context.IfNotNull(x => x.ComponentRegistry.IfNotNull(y => y.Dispose()));
        }

        #endregion
    }
}
